"""
音频服务实现
"""
import os
import random
import uuid
import time
import threading
import requests
import traceback
from typing import Dict, Any, List, Optional, Callable

from PyQt5.QtCore import QUrl, QObject, pyqtSignal, QTimer

from app.services.audio_service import IAudioService
from app.services.base_service import Event
from app.models.audio_item import AudioItem
from app.utils.logger import Logger
from app.services.main_speech_manager import MainSpeechManager
from app.services.service_locator import ServiceLocator
from app.services.config_service import IConfigService
from app.utils.speech_text_processor import SpeechTextProcessor
from app.config.app_config import AppConfig
from app.utils.pyaudio_player import PyAudioPlayer
from app.state.app_state_manager import AppStateManager
from app.state.state_types import StateType, StateValues
from app.models.status_monitor_model import StatusMonitorModel, StatusType as MonitorStatusType


class AudioService(IAudioService):
    """
    音频服务实现
    """
    
    def __init__(self):
        """
        初始化音频服务
        """
        super().__init__()
        
        # 获取日志记录器
        self.logger = Logger.get_logger("audio_service")
        
        # 获取 AppConfig 实例
        self.app_config = AppConfig.get_instance()
        
        # 从 AppConfig 获取 TTS 配置
        self.tts_url = self.app_config.get("tts", "url", "http://127.0.0.1:8080")
        self.tts_timeout = self.app_config.get("tts", "timeout", 30)
        self.check_interval_connected = self.app_config.get("tts", "check_interval_connected", 30)
        self.check_interval_disconnected = self.app_config.get("tts", "check_interval_disconnected", 5)
        
        self.logger.info(f"初始化音频服务，TTS URL: {self.tts_url}")
        
        # 音频队列
        self._queue: List[AudioItem] = []
        
        # 当前播放的音频项
        self._current_item: Optional[AudioItem] = None
        
        # 音量 - 默认设置为0.8而不是1.0，避免音量过高导致失真
        self._volume = 0.8
        
        # 音频输出设备
        self._output_device = "默认设备"
        
        # 音频设备详细信息
        self._device_info = None
        
        # 配置
        self._config: Dict[str, Any] = {
            "volume": 0.8,  # 默认音量降低为0.8
            "auto_play": False,  # 默认禁用自动播放
            "tts_url": self.tts_url,  # 使用从 AppConfig 读取的 TTS URL
            "tts_timeout": self.tts_timeout,  # 使用从 AppConfig 读取的超时时间
            "check_interval_connected": self.check_interval_connected,  # 使用从 AppConfig 读取的检测间隔
            "check_interval_disconnected": self.check_interval_disconnected  # 使用从 AppConfig 读取的检测间隔
        }
        
        # 播放模式: 固定为循环播放(loop)，移除了其他模式选项
        self._play_mode = "loop"  # 始终使用循环播放模式
        
        # 播放历史，用于循环播放模式
        self._play_history: List[AudioItem] = []
        self._history_max_size = 50  # 最多保存的历史记录数量
        
        # TTS服务连接状态
        self._tts_connected = False
        
        # TTS连接检测线程
        self._tts_check_thread = None
        self._tts_check_running = False
        
        # 主话术管理器
        self.main_speech_manager: Optional[MainSpeechManager] = None
        
        # 播放线程
        self._play_thread: Optional[threading.Thread] = None
        
        # 是否正在运行
        self._running = False
        
        # 是否暂停
        self._paused = False
        
        # 事件监听器字典，键为事件类型，值为监听器列表
        self._listeners: Dict[str, List[Callable[[Event], None]]] = {}
        
        # 初始化媒体播放器 - 使用PyAudioPlayer
        self._media_player = PyAudioPlayer(self.logger)
        
        # 设置初始音量
        self._media_player.set_volume(self._volume)
        self.logger.info(f"音频服务初始化完成，默认音量: {self._volume}")
        
        # 连接信号
        self._media_player.playback_completed.connect(self._on_playback_completed)
        self._media_player.playback_error.connect(self._on_playback_error)
        self._media_player.state_changed.connect(self._on_state_changed)
        
        # 添加暂停标志，用于控制队列播放行为
        self._playback_paused = False
        
        # 添加"播放完当前音频后暂停"标志
        self._pause_after_current = False
        
        # 获取状态管理器
        self.state_manager = ServiceLocator.get(AppStateManager)
        if not self.state_manager:
            self.logger.warning("无法获取状态管理器，状态更新可能不正确")
            
        # 初始化媒体播放器
        # self._initialize_player()
    
    def add_listener(self, event_type: str, listener: Callable[[Event], None]) -> None:
        """
        添加事件监听器
        
        @param event_type: 事件类型
        @param listener: 监听器函数，接收一个 Event 参数
        """
        if event_type not in self._listeners:
            self._listeners[event_type] = []
        self._listeners[event_type].append(listener)
    
    def remove_listener(self, event_type: str, listener: Callable[[Event], None]) -> bool:
        """
        移除事件监听器
        
        @param event_type: 事件类型
        @param listener: 监听器函数
        @return: 是否成功移除
        """
        if event_type in self._listeners and listener in self._listeners[event_type]:
            self._listeners[event_type].remove(listener)
            return True
        return False
    
    def clear_listeners(self, event_type: str = None) -> None:
        """
        清空监听器
        
        @param event_type: 事件类型，如果为None则清空所有类型的监听器
        """
        if event_type:
            if event_type in self._listeners:
                self._listeners[event_type] = []
        else:
            self._listeners.clear()
    
    def notify(self, event_type: str, data: Any = None) -> None:
        """
        触发事件
        
        @param event_type: 事件类型
        @param data: 事件数据
        """
        if event_type in self._listeners:
            event = Event(event_type, data)
            for listener in self._listeners[event_type][:]:  # 使用副本迭代，避免在回调中修改列表
                try:
                    listener(event)
                except Exception as e:
                    self.logger.error(f"调用事件监听器异常: {str(e)}")
                    traceback.print_exc()

    def play(self, audio_path: str, volume: Optional[float] = None) -> bool:
        """
        播放音频
        
        @param audio_path: 音频路径
        @param volume: 音量，如果为None则使用当前音量
        @return: 是否成功播放
        """
        try:
            # 检查文件是否存在
            if not audio_path or not os.path.exists(audio_path):
                self.logger.warning(f"音频文件不存在: {audio_path}")
                return False
            
            # 停止当前播放
            self.stop_playback()
            
            # 设置音量
            if volume is not None:
                self.set_volume(volume)
            
            # 使用媒体播放器播放音频
            result = self._media_player.play(audio_path)
            
            if result:
                self.logger.info(f"开始播放音频: {audio_path}")
            else:
                self.logger.warning(f"播放音频失败: {audio_path}")
            
            return result
        except Exception as e:
            self.logger.error(f"播放音频异常: {str(e)}")
            traceback.print_exc()
            return False

    def play_item(self, audio_item: AudioItem) -> bool:
        """
        播放音频项
        
        @param audio_item: 音频项
        @return: 是否成功播放
        """
        try:
            # 检查文件是否存在
            if not audio_item.file_path or not os.path.exists(audio_item.file_path):
                self.logger.warning(f"音频项的文件不存在: {audio_item.file_path}")
                return False
            
            # 记录文件信息
            file_size = os.path.getsize(audio_item.file_path) / 1024  # KB
            self.logger.info(f"准备播放音频文件: {audio_item.file_path}, 大小: {file_size:.2f} KB")
            
            # 停止当前播放
            self.stop_playback()
            
            # 设置当前播放的音频项
            self._current_item = audio_item
            self._current_item.is_playing = True
            self._current_item.is_paused = False
            
            # 触发播放开始事件
            self.notify("audio_playback_started", self._current_item)
            
            # 记录播放信息
            self.logger.info(f"开始播放音频项: {audio_item.title[:30]}...")
            
            # 获取并设置音量 - 增加一些安全检查
            if "volume" in audio_item.metadata:
                volume = audio_item.metadata["volume"]
                # 确保音量在合理范围内
                volume = max(0.0, min(0.95, float(volume)))  # 上限设为0.95避免爆音
                self._media_player.set_volume(volume)
                self.logger.info(f"使用音频项指定的音量: {volume}")
            else:
                # 使用当前音量，但确保不超过0.95
                safe_volume = min(0.95, self._volume)
                if safe_volume != self._volume:
                    self.logger.info(f"音量已从 {self._volume} 调整为 {safe_volume} 以防止爆音")
                self._media_player.set_volume(safe_volume)
                self.logger.info(f"使用当前音量播放: {safe_volume}")
            
            # 播放音频
            result = self._media_player.play(audio_item.file_path)
            
            if not result:
                self.logger.warning(f"播放音频项失败: {audio_item.title[:30]}...")
                if self._current_item:
                    self._current_item.error = "播放失败"
                    self.notify("audio_playback_failed", self._current_item)
                    self._current_item = None
            
            return result
        except Exception as e:
            self.logger.error(f"播放音频项异常: {str(e)}")
            traceback.print_exc()
            if self._current_item:
                self._current_item.error = str(e)
                self.notify("audio_playback_failed", self._current_item)
                self._current_item = None
            return False

    def stop_playback(self) -> bool:
        """
        停止播放
        
        @return: 是否成功停止
        """
        try:
            # 如果当前没有播放，则直接返回
            if not self._current_item:
                return True
            
            # 停止媒体播放器
            result = self._media_player.stop()
            
            # 如果当前有播放项，触发停止事件
            if self._current_item:
                # 创建副本用于事件通知
                stopped_item = self._current_item.copy()
                stopped_item.is_playing = False
                stopped_item.is_paused = False
                
                # 清空当前播放项
                self._current_item = None
                
                # 触发播放停止事件
                self.notify("audio_playback_stopped", stopped_item)
            
            return True
        except Exception as e:
            self.logger.error(f"停止播放异常: {str(e)}")
            traceback.print_exc()
            return False

    def pause_playback(self, after_current: bool = True) -> bool:
        """
        暂停播放
        
        @param after_current: 是否在当前音频播放完成后暂停，True表示播放完当前音频后暂停，False表示立即暂停
        @return: 是否成功暂停
        """
        try:
            # 如果当前没有播放，则直接返回
            if not self._current_item or not self._current_item.is_playing or self._current_item.is_paused:
                return False
            
            if after_current:
                # 设置"播放完当前音频后暂停"标志
                self._pause_after_current = True
                self.logger.info(f"已设置在当前音频播放完成后暂停: {self._current_item.title[:30]}...")
                
                # 更新状态管理器
                if self.state_manager:
                    from app.state.state_types import StateType, StateValues
                    self.state_manager.set_state(StateType.PLAYBACK, StateValues.PLAYING)
                
                # 触发事件，通知UI更新
                self.notify("audio_will_pause_after_current", self._current_item)
                
                return True
            else:
                # 设置暂停标志，阻止自动播放下一条
                self._playback_paused = True
                self._pause_after_current = False
                
                # 暂停媒体播放器
                result = self._media_player.pause()
                
                if result:
                    # 更新播放状态
                    self._current_item.is_paused = True
                    
                    # 触发播放暂停事件
                    self.notify("audio_playback_paused", self._current_item)
                    
                    # 更新状态管理器
                    if self.state_manager:
                        from app.state.state_types import StateType, StateValues
                        self.state_manager.set_state(StateType.PLAYBACK, StateValues.PAUSED)
                    
                    self.logger.info(f"已立即暂停播放: {self._current_item.title[:30]}...")
                
                return result
                
        except Exception as e:
            self.logger.error(f"暂停播放异常: {str(e)}")
            traceback.print_exc()
            return False

    def resume_playback(self) -> bool:
        """
        恢复播放
        
        @return: 是否成功恢复播放
        """
        try:
            # 清除暂停标志
            self._playback_paused = False
            # 清除"播放完当前音频后暂停"标志
            self._pause_after_current = False
            
            # 如果当前有暂停的项目，恢复播放
            if self._current_item and self._current_item.is_paused:
                # 尝试恢复播放
                result = self._media_player.resume()
                
                if result:
                    # 更新播放状态
                    self._current_item.is_paused = False
                    
                    # 媒体播放器的resume方法内部已经会设置状态为PLAYING，不需要额外设置
                    
                    # 触发播放恢复事件
                    self.notify("audio_playback_resumed", self._current_item)
                    
                    # 更新状态管理器
                    if self.state_manager:
                        self.state_manager.set_state(StateType.PLAYBACK, StateValues.PLAYING)
                    
                    self.logger.info(f"恢复播放: {self._current_item.title[:30]}...")
                    return True
                else:
                    self.logger.warning("恢复播放失败")
                    return False
            # 如果没有当前播放项但队列不为空，开始播放下一项
            elif self._queue and not self._current_item:
                self.logger.info("没有已暂停的音频，但队列不为空，开始播放下一项")
                return self._play_next()
            else:
                self.logger.warning("没有已暂停的音频且队列为空，无法恢复播放")
                return False
                
        except Exception as e:
            self.logger.error(f"恢复播放异常: {str(e)}")
            self.logger.error(traceback.format_exc())
            return False

    def is_playing(self) -> bool:
        """
        检查是否正在播放
        
        @return: 是否正在播放
        """
        try:
            # 检查当前播放状态
            return self._media_player.get_state() == "PLAYING"
        except Exception as e:
            self.logger.error(f"检查播放状态异常: {str(e)}")
            traceback.print_exc()
            return False

    def add_to_queue(self, audio_item: AudioItem) -> None:
        """
        将音频添加到播放队列底部
        
        @param audio_item: 音频项
        """
        # 添加到队列
        self._queue.append(audio_item)
        
        # 在单独的线程中触发队列更新事件，避免阻塞UI线程
        threading.Thread(
            target=lambda: self.notify("audio_queue_updated", self._queue.copy()),
            daemon=True
        ).start()
        
        self.logger.debug(f"已添加音频到队列底部: {audio_item.title}")
    
    def add_to_queue_front(self, audio_item: AudioItem) -> None:
        """
        将音频添加到播放队列顶部（临时插入）
        
        @param audio_item: 音频项
        """
        # 找到队列中所有临时项目的最后位置
        temp_items_end_index = 0
        for i, item in enumerate(self._queue):
            if item.metadata and item.metadata.get("is_temporary", False):
                temp_items_end_index = i + 1
        
        # 插入到临时项目区域的末尾
        self._queue.insert(temp_items_end_index, audio_item)
        
        # 在单独的线程中触发队列更新事件，避免阻塞UI线程
        threading.Thread(
            target=lambda: self.notify("audio_queue_updated", self._queue.copy()),
            daemon=True
        ).start()
        
        self.logger.debug(f"已添加临时音频到队列顶部区域: {audio_item.title}")
    
    def remove_from_queue(self, item_id: str) -> bool:
        """
        从播放队列中移除音频
        
        @param item_id: 音频项 ID
        @return: 是否成功移除
        """
        # 查找音频项
        for i, item in enumerate(self._queue):
            if item.id == item_id:
                # 从队列中移除
                self._queue.pop(i)
                
                # 触发队列更新事件
                self.notify("audio_queue_updated", self._queue)
                
                self.logger.debug(f"已从队列中移除音频: {item.title}")
                return True
        
        return False
    
    def clear_queue(self) -> None:
        """
        清空播放队列
        """
        # 清空队列
        self._queue.clear()
        
        # 触发队列更新事件
        self.notify("audio_queue_updated", self._queue)
        
        self.logger.debug("已清空播放队列")
    
    def get_queue(self) -> List[AudioItem]:
        """
        获取播放队列
        
        @return: 播放队列
        """
        return self._queue.copy()
    
    def get_current_item(self) -> Optional[AudioItem]:
        """
        获取当前播放的音频项
        
        @return: 当前播放的音频项，如果没有则返回 None
        """
        return self._current_item
    
    def set_volume(self, volume: float) -> None:
        """
        设置音量
        
        @param volume: 音量值，范围 0.0-1.0
        """
        # 确保音量在有效范围内
        volume = max(0.0, min(1.0, volume))
        
        # 设置音量
        self._volume = volume
        self._config["volume"] = volume
        
        # 更新媒体播放器的音量
        self._media_player.set_volume(volume)
        
        # 触发音量变化事件
        self.notify("audio_volume_changed", volume)
        
        self.logger.debug(f"已设置音量: {volume}")
    
    def get_volume(self) -> float:
        """
        获取当前音量
        
        @return: 当前音量值
        """
        return self._volume
    
    def set_output_device(self, output_device: str) -> None:
        """
        设置音频输出设备
        
        @param output_device: 输出设备名称
        """
        self._set_output_device(output_device)
    
    def configure(self, config: Dict[str, Any]) -> None:
        """
        配置音频服务
        
        @param config: 配置字典
        """
        # 记录配置内容，方便调试
        self.logger.debug(f"AudioService收到配置: {config}")
        
        # 配置音频服务
        for key, value in config.items():
            # 忽略播放模式配置，确保始终使用循环播放模式
            if key == "play_mode":
                self.logger.info("忽略播放模式配置，系统固定使用循环播放模式")
                continue
                
            self._config[key] = value
            
            # 对特定配置项进行特殊处理
            if key == "volume":
                # 确保音量在有效范围内
                volume = max(0.0, min(1.0, float(value)))
                # 设置音量
                self._volume = volume
                # 更新媒体播放器的音量
                self._media_player.setVolume(int(volume * 100))
                self.logger.info(f"通过配置更新音量: {volume}")
                # 触发音量变化事件
                self.notify("audio_volume_changed", volume)
            # 额外处理话术间隔时间配置
            elif key == "speech_interval_min" or key == "speech_interval_max":
                # 确保更新值是整数
                if isinstance(value, str):
                    value = int(value)
                self._config[key] = value
                self.logger.info(f"通过配置更新话术间隔时间 {key}: {value}毫秒")
            # 直接处理tts_url配置
            elif key == "tts_url":
                self._config["tts_url"] = value
                self.logger.info(f"通过配置更新TTS URL: {value}")
                # 立即更新AppConfig
                from app.config.app_config import AppConfig
                app_config = AppConfig.get_instance()
                app_config.set("tts", "url", value)
                # 立即检查TTS连接
                self._check_tts_connection()
            # 处理嵌套的tts配置
            elif key == "tts" and isinstance(value, dict):
                if "url" in value:
                    self._config["tts_url"] = value["url"]
                    self.logger.info(f"通过嵌套配置更新TTS URL: {value['url']}")
                    # 立即更新AppConfig
                    from app.config.app_config import AppConfig
                    app_config = AppConfig.get_instance()
                    app_config.set("tts", "url", value["url"])
                    # 立即检查TTS连接
                    self._check_tts_connection()
            
        # 如果配置中包含output_device，则更新输出设备
        if "output_device" in config:
            self._set_output_device(config["output_device"])
        
        # 获取配置服务
        config_service = ServiceLocator.get(IConfigService)
        
        # 使用统一的方法初始化主话术管理器
        self._initialize_main_speech_manager()
        
        # 获取关键词功能状态
        keyword_enabled = config.get("keyword_enabled")
        if keyword_enabled is None and config_service:
            keyword_enabled = config_service.get("keyword.enabled", False)
        
        # 初始化或更新关键词话术管理器
        if keyword_enabled:
            try:
                from app.services.keyword_speech_manager import KeywordSpeechManager
                
                # 获取配置路径
                config_path = None
                if config_service:
                    config_path = config_service.get("config_path")
                    
                    if not config_path:
                        config_path = config_service.get("config_dir")
                
                if not config_path:
                    self.logger.warning("无法获取配置路径，无法初始化关键词话术管理器")
                    return
                
                # 检查是否需要创建或更新关键词话术管理器
                if not hasattr(self, 'keyword_speech_manager') or not self.keyword_speech_manager:
                    self.keyword_speech_manager = KeywordSpeechManager(config_path)
                    self.logger.info(f"已初始化关键词话术管理器，配置路径: {config_path}")
                elif self.keyword_speech_manager.config_path != config_path:
                    self.keyword_speech_manager = KeywordSpeechManager(config_path)
                    self.logger.info(f"已更新关键词话术管理器配置路径: {config_path}")
                else:
                    self.keyword_speech_manager.reload()
                    self.logger.info(f"已重新加载关键词话术，配置路径: {config_path}")
            except Exception as e:
                self.logger.error(f"初始化关键词话术管理器失败: {str(e)}")
                traceback.print_exc()
        else:
            self.logger.info("关键词功能已禁用，不初始化关键词话术管理器")
        
        # 初始化TTS相关配置
        if config_service:
            # 获取TTS配置
            tts_url = config_service.get("tts.url") or "http://localhost:9000/tts"
            tts_api_key = config_service.get("tts.api_key") or ""
            tts_timeout = config_service.get("tts.timeout") or 10
            
            # 更新配置
            self._config["tts_url"] = tts_url
            self._config["tts_api_key"] = tts_api_key
            self._config["tts_timeout"] = tts_timeout
            
            # 检查TTS服务连接状态
            is_connected = self._check_tts_connection()
            if is_connected:
                self.logger.info(f"TTS服务连接成功: {tts_url}")
                self._tts_connected = True
            else:
                self.logger.warning(f"TTS服务连接失败: {tts_url}")
                self._tts_connected = False
            
            # 更新TTS连接状态
            connection_status = StateValues.CONNECTED if is_connected else StateValues.DISCONNECTED
            
            # 同时通过状态管理器和事件系统更新状态
            if self.state_manager:
                self.state_manager.set_state(StateType.AUDIO_SERVICE, connection_status)
            
            # 触发TTS连接状态事件
            self.notify("audio_service_status_changed", "已连接" if is_connected else "未连接")
            
            # 启动TTS连接检查线程
            self._start_tts_check_thread()
        
        # 从配置服务获取音频输出设备设置
        if config_service:
            # 获取设备名称
            output_device = config_service.get("audio.output")  # 与ConfigPanel中的键名保持一致
            if output_device:
                # 应用输出设备设置
                self._set_output_device(output_device)
                self.logger.info(f"从配置服务加载音频输出设备: {output_device}")
        
        self.logger.info("音频服务配置已更新")
    
    def start(self) -> bool:
        """
        启动服务
        
        @return: 是否成功启动
        """
        if self._running:
            self.logger.warning("音频服务已经在运行")
            return True
        
        try:
            # 设置运行标志
            self._running = True
            
            # 启动播放线程
            self._play_thread = threading.Thread(target=self._play_loop, daemon=True)
            self._play_thread.start()
            
            # 检查TTS服务连接状态
            is_connected = self._check_tts_connection()
            
            self.logger.info("音频服务已启动")
            return True
        except Exception as e:
            self.logger.error(f"启动音频服务失败: {str(e)}")
            traceback.print_exc()
            self._running = False
            return False
    
    def stop(self) -> bool:
        """
        停止服务
        
        @return: 是否成功停止
        """
        try:
            # 检查是否正在运行
            if not self._running:
                return True
            
            # 停止主线程
            self._running = False
            
            # 等待线程结束
            if self._play_thread:
                self._play_thread.join(2.0)  # 等待最多2秒
                self._play_thread = None
            
            # 停止媒体播放器
            self._media_player.stop()
            
            # 清除队列
            self._queue.clear()
            
            # 停止当前播放
            if self._current_item:
                self._stop_current()
            
            # 设置运行标志
            self._running = False
            
            self.logger.info("音频服务已停止")
            return True
        except Exception as e:
            self.logger.error(f"停止音频服务失败: {str(e)}")
            traceback.print_exc()
            return False
    
    def shutdown(self) -> None:
        """
        关闭服务
        """
        self.logger.info("音频服务正在关闭...")
        
        # 停止服务
        self.stop()
        
        # 清空队列
        self.clear_queue()
        
        # 清空监听器
        self.clear_listeners()
        
        self.logger.info("音频服务已关闭")
    
    def _play_loop(self) -> None:
        """
        播放循环
        """
        while self._running:
            try:
                # 如果当前没有播放，且队列不为空，且auto_play为True，则播放下一个
                if not self._current_item and self._queue and self._config.get("auto_play", False):
                    self._play_next()
                
                # 休眠一段时间，避免CPU占用过高
                time.sleep(0.1)
            except Exception as e:
                self.logger.error(f"播放循环异常: {str(e)}")
                traceback.print_exc()
    
    def _play_next(self) -> bool:
        """
        播放下一个音频
        
        @return: 是否成功播放
        """
        try:
            # 如果队列为空，则直接返回
            if not self._queue:
                self.logger.debug("队列为空，无法播放下一个")
                return False
            
            # 获取队列中的第一个音频项并从队列中移除
            audio_item = self._queue.pop(0)
            
            # 如果有文件路径，则使用_play_audio方法播放
            if audio_item.file_path and os.path.exists(audio_item.file_path):
                self.logger.info(f"播放队列中的音频: {audio_item.title[:30]}...")
                success = self._play_audio(audio_item)
                
                # 如果成功播放，则更新队列显示
                if success:
                    # 更新队列显示（移除已播放的项目）
                    self.notify("audio_queue_updated", self._queue)
                
                return success
            else:
                # 如果没有文件路径，记录警告并跳过
                self.logger.warning(f"音频项没有有效的文件路径，无法播放: {audio_item.title[:30]}...")
                
                # 检查是否正在生成音频
                is_generating = audio_item.metadata.get("generating_audio", False)
                
                # 处理没有音频文件的项目
                if is_generating:
                    # 如果正在生成，添加到队列前部但不是最前面，避免一直卡在同一项目
                    if len(self._queue) > 0:
                        self._queue.insert(1, audio_item)
                        self.logger.info(f"项目正在生成音频，已移至队列次前位置: {audio_item.title[:30]}...")
                    else:
                        self.add_to_queue(audio_item)
                        self.logger.info(f"项目正在生成音频，已移至队列末尾: {audio_item.title[:30]}...")
                else:
                    # 如果没有生成，则添加到队列末尾
                    self.add_to_queue(audio_item)
                    self.logger.info(f"项目没有音频且未生成，已移至队列末尾: {audio_item.title[:30]}...")
                
                # 更新队列显示
                self.notify("audio_queue_updated", self._queue)
                
                # 确保队列前两项有音频文件
                self._ensure_front_items_have_audio()
                
                # 如果队列不为空，则递归尝试播放下一个
                if self._queue:
                    return self._play_next()
                
                return False
        except Exception as e:
            self.logger.error(f"播放下一个音频失败: {str(e)}")
            traceback.print_exc()
            return False
    
    def _auto_insert_next_speech(self) -> None:
        """
        自动插入下一条主话术
        """
        try:
            # 检查主话术管理器是否可用
            if not self.main_speech_manager:
                self.logger.warning("主话术管理器不可用，无法自动插入主话术")
                return
            
            # 初始化话术文件索引（如果不存在）
            if not hasattr(self, '_speech_file_index'):
                self._speech_file_index = 0
            
            # 获取所有主话术文件
            speech_files = list(self.main_speech_manager._main_speeches.keys())
            if not speech_files:
                self.logger.warning("主话术文件列表为空，无法自动插入主话术")
                return
            
            # 按照文件名中的数字进行排序
            def extract_number(filename):
                # 提取文件名中的数字部分
                import re
                
                # 先尝试破折号格式（如01-产品名称.txt）
                dash_match = re.match(r'^(\d+)-', filename)
                if dash_match:
                    return int(dash_match.group(1))
                
                # 尝试x.y格式（如1.0.txt, 3.0{停顿}.txt）
                dot_match = re.match(r'^(\d+\.\d+)', filename)
                if dot_match:
                    return float(dot_match.group(1))
                
                # 尝试纯数字格式（如1.txt, 2.txt）
                num_match = re.match(r'^(\d+)\.', filename)
                if num_match:
                    return int(num_match.group(1))
                    
                # 如果无法提取排序键，则返回一个很大的数，使其排在最后
                self.logger.debug(f"文件'{filename}'无法提取排序键，将排在最后")
                return float('inf')
            
            # 在排序前添加日志
            self.logger.info(f"排序前的文件列表: {speech_files}")
            
            # 按照数字顺序排序
            speech_files = sorted(speech_files, key=extract_number)
            
            # 在排序后添加日志
            self.logger.info(f"排序后的文件列表: {speech_files}")
            
            # 按顺序选择文件
            file_name = speech_files[self._speech_file_index]
            self._speech_file_index = (self._speech_file_index + 1) % len(speech_files)
            
            # 获取文件内容
            content = self.main_speech_manager._main_speeches[file_name]
            
            # 将内容按行分割
            lines = [line.strip() for line in content.split('\n') if line.strip()]
            if not lines:
                self.logger.warning(f"主话术文件 {file_name} 没有有效行")
                return
            
            # 随机选择一行作为话术内容
            speech_content = random.choice(lines)
                        
            self.logger.info(f"从文件 {file_name} 中随机选择一行: {speech_content[:20]}...")
            
            if not speech_content:
                self.logger.warning("获取主话术失败，无法自动插入主话术")
                return
            
            # 注：文本内容处理将在UI层完成，这里只负责选择并传递原始文本
            
            # 创建音频项
            audio_item = AudioItem(
                id=str(uuid.uuid4()),
                file_path="",
                title=speech_content,  # 使用原始文本，UI层会处理变量替换
                source_type="main_speech",
                metadata={
                    "original_type": "主话术", 
                    "is_temporary": False,
                    "file_name": file_name,
                    "original_text": speech_content  # 保存原始文本
                }
            )
            
            # 添加到队列底部
            self.add_to_queue(audio_item)
            
            self.logger.info(f"已自动插入主话术: {speech_content[:50]}...")
        except Exception as e:
            self.logger.error(f"自动插入主话术失败: {str(e)}")
            traceback.print_exc()
    
    def _is_valid_for_cycle(self, audio_item) -> bool:
        """
        判断音频项是否符合基本循环条件
        
        @param audio_item: 音频项
        @return: 是否符合基本循环条件
        """
        if not audio_item or not audio_item.metadata:
            return False
            
        # 临时话术不加入循环
        if audio_item.metadata.get("is_temporary", False):
            return False
            
        # 错误的音频不加入循环
        if audio_item.error:
            return False
            
        # 如果没有文件路径或文件不存在，不加入循环
        if not audio_item.file_path or not os.path.exists(audio_item.file_path):
            return False
            
        # 注意：主话术的特殊处理已移至_on_playback_completed方法
        return True
        
    def _on_playback_completed(self) -> None:
        """
        播放完成处理
        """
        try:
            # 如果当前没有播放，则直接返回
            if not self._current_item:
                return
            
            # 获取当前播放的音频项
            audio_item = self._current_item
            
            # 清除当前播放的音频项
            self._current_item = None
            
            # 检查是否为临时话术
            is_temporary = audio_item.metadata and audio_item.metadata.get("is_temporary", False)
            
            # 触发播放完成事件
            self.notify("audio_playback_completed", audio_item)
            
            # 判断是否为主话术
            is_main_speech = (audio_item.source_type == "main_speech" or 
                             (audio_item.metadata and audio_item.metadata.get("original_type", "") == "主话术"))
            
            # 根据不同类型处理循环播放逻辑
            if is_temporary:
                self.logger.debug(f"临时话术播放完成，不加入队列: {audio_item.title[:30]}...")
            elif is_main_speech:
                # 主话术应当获取新的随机话术而不是复制
                self.logger.info(f"主话术播放完成，将获取新的随机话术加入队列")
                self._auto_insert_next_speech()  # 获取新的随机话术
            elif self._is_valid_for_cycle(audio_item):
                # 其他普通音频复制加入队列尾部
                recycled_item = audio_item.copy()
                self.logger.info(f"将普通音频添加到队列尾部循环播放: {recycled_item.title[:30]}...")
                self.add_to_queue(recycled_item)
            else:
                self.logger.debug(f"音频项不符合循环播放条件，不加入队列: {audio_item.title[:30]}...")
            
            # 确保队列前两项有音频文件
            self._ensure_front_items_have_audio()
            
            # 检查是否需要在当前音频播放完成后暂停
            if self._pause_after_current:
                self.logger.info("当前音频已播放完成，根据设置进入暂停状态")
                # 设置暂停标志
                self._playback_paused = True
                # 清除"播放完当前音频后暂停"标志
                self._pause_after_current = False
                
                # 更新状态管理器
                if self.state_manager:
                    from app.state.state_types import StateType, StateValues
                    self.state_manager.set_state(StateType.PLAYBACK, StateValues.PAUSED)
                
                # 触发播放暂停事件
                self.notify("audio_playback_paused", audio_item)
                return
            
            # 检查是否处于暂停状态
            if self._playback_paused:
                self.logger.info("当前处于暂停状态，不自动播放下一项")
                
                # 更新状态管理器
                if self.state_manager:
                    from app.state.state_types import StateType, StateValues
                    self.state_manager.set_state(StateType.PLAYBACK, StateValues.PAUSED)
                    
                return
            
            # 如果队列不为空，则播放下一个
            if self._queue:
                # 在单独的线程中播放下一个，避免阻塞UI线程
                threading.Thread(target=self._play_next_thread, daemon=True).start()
            elif not is_temporary:
                # 如果队列为空(罕见情况)，并且不是临时话术，则自动插入新话术
                self.logger.debug(f"队列为空，自动插入新话术")
                # 在单独的线程中自动插入新话术，避免阻塞UI线程  
                threading.Thread(target=self._auto_insert_next_speech_thread, daemon=True).start()
            else:
                self.logger.debug(f"临时话术播放完成，队列为空，不插入新话术")
            
        except Exception as e:
            self.logger.error(f"处理播放完成失败: {str(e)}")
            traceback.print_exc()
            
            # 如果处理失败，则触发播放失败事件
            if audio_item:
                audio_item.error = str(e)
                self.notify("audio_playback_failed", audio_item)
    
    def _ensure_front_items_have_audio(self) -> None:
        """
        确保队列前两项都有音频文件
        """
        try:
            if not self._queue:
                return
            
            # 获取队列中前两个项目
            front_items = self._queue[:min(2, len(self._queue))]
            
            # 查找没有音频文件的项目
            items_to_generate = []
            for item in front_items:
                if not item.file_path or not os.path.exists(item.file_path):
                    items_to_generate.append(item)
            
            if not items_to_generate:
                return  # 所有项目都有音频文件
            
            self.logger.info(f"检测到队列前两项中有 {len(items_to_generate)} 个项目需要生成音频")
            
            # 从配置获取语音服务
            from app.services.speech_service import ISpeechService
            from app.services.service_locator import ServiceLocator
            
            speech_service = ServiceLocator.get(ISpeechService)
            if not speech_service:
                self.logger.warning("无法获取语音服务，无法生成音频")
                return
            
            # 获取最新配置
            config = AppConfig.get_instance()
            
            # 从ConfigService获取最新配置，确保使用最新设置
            config_service = ServiceLocator.get(IConfigService)
            
            # 获取最新的音色设置
            if config_service:
                # 从配置服务获取最新设置
                host_voice = config_service.get("speech.host_voice", "1女10号模型")
                assist_voice = config_service.get("speech.assist_voice", "1女10号模型")  # 保留，暂不使用
                self.logger.info(f"从配置服务获取音色设置: 主播={host_voice}, 辅助={assist_voice}")
            else:
                # 从AppConfig获取设置
                host_voice = config.get("speech", "host_voice", "1女10号模型")
                assist_voice = config.get("speech", "assist_voice", "1女10号模型")  # 保留，暂不使用
            
            self.logger.info(f"当前音色设置：主播音色={host_voice}，辅助音色={assist_voice}，使用主播音色")
            
            # 为每个需要生成音频的项目生成音频
            for item in items_to_generate:
                # 标记为正在生成
                item.metadata["generating_audio"] = True
                
                # 注：文本内容已在UI层处理完毕，这里直接使用item.title
                processed_text = item.title
                
                self.logger.info(f"生成队列项音频，文本: {processed_text[:50]}...")
                
                # 获取项目类型（仅用于日志记录）
                item_type = item.metadata.get("original_type", "未知")
                
                # 所有类型都使用主播音色
                speaker = host_voice
                
                self.logger.info(f"使用主播音色生成音频：{speaker}，项目类型：{item_type}")
                
                # 定义完成回调
                def create_callback(current_item):
                    def on_speech_completed(text, file_path):
                        if file_path:
                            self.logger.info(f"队列前两项音频生成完成: {text[:30]}..., 文件路径: {file_path}")
                            
                            # 更新文件路径
                            current_item.file_path = file_path
                            current_item.metadata.pop("generating_audio", None)
                            
                            # 触发队列更新事件
                            self.notify("audio_queue_updated", self._queue)
                        else:
                            self.logger.error(f"队列前两项音频生成失败: {text[:30]}...")
                    
                    return on_speech_completed
                
                # 调用异步方法生成语音
                speech_service.synthesize_async(
                    text=processed_text,  # 使用已处理的文本
                    speaker=speaker,      # 使用音色
                    completion_callback=create_callback(item)
                )
        except Exception as e:
            self.logger.error(f"确保队列前两项有音频文件失败: {str(e)}")
            traceback.print_exc()
    
    def _auto_insert_next_speech_thread(self) -> None:
        """
        在单独的线程中自动插入下一条主话术
        """
        try:
            self._auto_insert_next_speech()
        except Exception as e:
            self.logger.error(f"线程中自动插入主话术失败: {str(e)}")
            traceback.print_exc()
    
    def _play_next_thread(self) -> None:
        """
        在单独的线程中播放下一个音频
        """
        try:
            # 获取话术间隔时间范围
            speech_interval_min = self._config.get("speech_interval_min", 100)
            speech_interval_max = self._config.get("speech_interval_max", 1000)
            
            # 确保范围有效
            if speech_interval_min > speech_interval_max:
                speech_interval_min, speech_interval_max = speech_interval_max, speech_interval_min
            
            # 生成随机延迟（范围：最小值到最大值）
            if speech_interval_max > 0:
                delay = random.randint(speech_interval_min, speech_interval_max)
                if delay > 0:
                    self.logger.info(f"话术间隔延迟：{delay}毫秒")
                    # 将毫秒转换为秒
                    time.sleep(delay / 1000.0)
            
            # 播放下一个音频
            self._play_next()
        except Exception as e:
            self.logger.error(f"线程中播放下一个音频失败: {str(e)}")
            traceback.print_exc()
    
    def start_playback(self) -> bool:
        """
        手动开始播放
        
        @return: 是否成功开始播放
        """
        try:
            # 如果当前已经在播放，则直接返回
            if self._current_item and self._current_item.is_playing and not self._current_item.is_paused:
                return True
            
            # 如果当前有暂停的项目，则恢复播放
            if self._current_item and self._current_item.is_paused:
                return self.resume_playback()
            
            # 如果队列为空，则直接返回
            if not self._queue:
                self.logger.warning("播放队列为空，无法开始播放")
                return False
            
            # 确保队列前两项有音频文件
            self._ensure_front_items_have_audio()
            
            # 开始播放下一个
            self._play_next()
            
            self.logger.debug("已手动开始播放")
            return True
        except Exception as e:
            self.logger.error(f"手动开始播放失败: {str(e)}")
            traceback.print_exc()
            return False
    
    def _check_tts_connection(self):
        """
        检查TTS服务连接状态
        
        @return: 是否连接成功
        """
        # 从 AppConfig 获取最新的 TTS 配置
        self.tts_url = self.app_config.get("tts", "url", "http://127.0.0.1:8080")
        self.tts_timeout = self.app_config.get("tts", "timeout", 30)
        
        # 更新内部配置
        self._config["tts_url"] = self.tts_url
        self._config["tts_timeout"] = self.tts_timeout
        
        # 尝试发送请求到TTS服务
        try:
            # 记录开始时间
            start_time = time.time()
            
            # 发送GET请求（只检查服务是否可用，不需要实际合成语音）
            response = requests.get(f"{self.tts_url}/status", timeout=self.tts_timeout)
            
            # 计算响应时间
            response_time = time.time() - start_time
            
            # 简化状态码判断：只要不是500系列错误，就认为服务在线
            # 200表示成功，400表示参数错误但服务在线
            if response.status_code < 500:
                if not self._tts_connected:
                    self.logger.info(f"TTS服务连接成功: {self.tts_url}")
                    self._tts_connected = True
                    # 更新状态管理器
                    if hasattr(self, 'state_manager') and self.state_manager:
                        self.state_manager.set_state(StateType.AUDIO_SERVICE, StateValues.CONNECTED)
                    # 触发连接状态变化事件
                    self.notify("audio_service_status_changed", "已连接")
                return True
            else:
                # 500系列错误表示服务器内部错误
                if self._tts_connected:
                    self.logger.warning(f"TTS服务器错误: {response.status_code}")
                    self._tts_connected = False
                    # 更新状态管理器
                    if hasattr(self, 'state_manager') and self.state_manager:
                        self.state_manager.set_state(StateType.AUDIO_SERVICE, StateValues.DISCONNECTED)
                    # 触发连接状态变化事件
                    self.notify("audio_service_status_changed", "未连接")
                return False
        except requests.exceptions.Timeout:
            # 超时表示服务不可用
            if self._tts_connected:
                self.logger.warning(f"TTS服务连接超时: {self.tts_url}")
                self._tts_connected = False
                # 更新状态管理器
                if hasattr(self, 'state_manager') and self.state_manager:
                    self.state_manager.set_state(StateType.AUDIO_SERVICE, StateValues.DISCONNECTED)
                # 触发连接状态变化事件
                self.notify("audio_service_status_changed", "未连接")
            return False
        except requests.exceptions.ConnectionError:
            # 连接错误表示服务不可用
            if self._tts_connected:
                self.logger.warning(f"TTS服务连接错误: {self.tts_url}")
                self._tts_connected = False
                # 更新状态管理器
                if hasattr(self, 'state_manager') and self.state_manager:
                    self.state_manager.set_state(StateType.AUDIO_SERVICE, StateValues.DISCONNECTED)
                # 触发连接状态变化事件
                self.notify("audio_service_status_changed", "未连接")
            return False
        except Exception as e:
            # 其他异常表示服务不可用
            if self._tts_connected:
                self.logger.warning(f"TTS服务连接失败: {str(e)}")
                self._tts_connected = False
                # 更新状态管理器
                if hasattr(self, 'state_manager') and self.state_manager:
                    self.state_manager.set_state(StateType.AUDIO_SERVICE, StateValues.DISCONNECTED)
                # 触发连接状态变化事件
                self.notify("audio_service_status_changed", "未连接")
            return False
    
    def _start_tts_check_thread(self):
        """
        启动TTS连接检测线程
        """
        if self._tts_check_thread and self._tts_check_thread.is_alive():
            return
            
        self._tts_check_running = True
        self._tts_check_thread = threading.Thread(target=self._tts_check_loop, daemon=True)
        self._tts_check_thread.start()
        self.logger.info("TTS连接检测线程已启动")
    
    def _tts_check_loop(self):
        """
        TTS连接检测循环
        """
        while self._tts_check_running:
            # 检查TTS服务连接状态
            is_connected = self._check_tts_connection()
            
            # 根据连接状态决定下次检测的间隔时间
            if is_connected:
                # 已连接时使用较长的检测间隔
                interval = self.check_interval_connected
            else:
                # 未连接时使用较短的检测间隔
                interval = self.check_interval_disconnected
            
            # 等待指定时间后再次检测
            time.sleep(interval)
    
    def _on_state_changed(self, state):
        """
        处理媒体状态变化
        
        @param state: 媒体状态
        """
        if state == "STOPPED" and self._current_item:
            self.logger.info(f"媒体播放结束: {self._current_item.title[:30]}...")
            # 不在这里处理播放完成，而是在 _on_playback_completed 中处理
        elif state == "PLAYING" and self._current_item:
            self.logger.info(f"媒体开始播放: {self._current_item.title[:30]}...")
        elif state == "PAUSED" and self._current_item:
            self.logger.info(f"媒体暂停播放: {self._current_item.title[:30]}...")
    
    def _on_playback_error(self, error):
        """
        处理播放错误
        
        @param error: 错误信息
        """
        error_msg = "未知错误"
        if error == "ResourceError":
            error_msg = "资源错误"
        elif error == "FormatError":
            error_msg = "格式错误"
        elif error == "NetworkError":
            error_msg = "网络错误"
        elif error == "AccessDeniedError":
            error_msg = "访问被拒绝"
        elif error == "ServiceMissingError":
            error_msg = "服务缺失"
        elif error == "Device unavailable":
            error_msg = "设备不可用"
        
        self.logger.error(f"媒体播放错误: {error_msg}")
        
        if self._current_item:
            # 获取当前播放的音频项
            audio_item = self._current_item
            
            # 设置错误信息
            audio_item.error = error_msg
            
            # 触发播放失败事件
            self.notify("audio_playback_failed", audio_item)
            
            # 清除当前播放的音频项
            self._current_item = None
            
            # 检查是否为临时话术
            is_temporary = audio_item.metadata and audio_item.metadata.get("is_temporary", False)
            
            # 判断是否为主话术
            is_main_speech = (audio_item.source_type == "main_speech" or 
                             (audio_item.metadata and audio_item.metadata.get("original_type", "") == "主话术"))
            
            # 根据不同类型处理循环播放逻辑，与播放完成时相同
            if is_temporary:
                self.logger.debug(f"临时话术播放失败，不加入队列: {audio_item.title[:30]}...")
            elif is_main_speech:
                # 主话术应当获取新的随机话术而不是复制
                self.logger.info(f"主话术播放失败，将获取新的随机话术加入队列")
                self._auto_insert_next_speech()  # 获取新的随机话术
            elif self._is_valid_for_cycle(audio_item):
                # 其他普通音频复制加入队列尾部
                recycled_item = audio_item.copy()
                # 清除错误状态，确保下次可以播放
                recycled_item.error = None
                self.logger.info(f"普通音频播放失败，添加到队列尾部重试: {recycled_item.title[:30]}...")
                self.add_to_queue(recycled_item)
            else:
                self.logger.debug(f"音频项不符合循环播放条件，不加入队列: {audio_item.title[:30]}...")
            
            # 确保队列前两项有音频文件
            self._ensure_front_items_have_audio()
            
            # 如果队列不为空，则播放下一个
            if self._queue:
                # 在单独的线程中播放下一个，避免阻塞UI线程
                threading.Thread(target=self._play_next_thread, daemon=True).start()
            elif not is_temporary:
                # 如果队列为空(罕见情况)，并且不是临时话术，则自动插入新话术
                self.logger.debug(f"队列为空，自动插入新话术")
                # 在单独的线程中自动插入新话术，避免阻塞UI线程  
                threading.Thread(target=self._auto_insert_next_speech_thread, daemon=True).start()
            else:
                self.logger.debug(f"临时话术播放失败，队列为空，不插入新话术")
    
    def _play_audio(self, audio_item: AudioItem) -> bool:
        """
        播放音频文件
        
        @param audio_item: 音频项
        @return: 是否成功播放
        """
        try:
            # 检查文件是否存在
            if not audio_item.file_path or not os.path.exists(audio_item.file_path):
                self.logger.warning(f"音频文件不存在: {audio_item.file_path}")
                return False
            
            # 记录文件信息
            try:
                file_size = os.path.getsize(audio_item.file_path) / 1024  # KB
                self.logger.info(f"准备播放音频文件: {audio_item.file_path}, 大小: {file_size:.2f} KB")
            except Exception as e:
                self.logger.warning(f"获取文件信息失败: {str(e)}")
            
            # 设置当前播放的音频项
            self._current_item = audio_item
            self._current_item.is_playing = True
            self._current_item.is_paused = False
            
            # 触发播放开始事件
            self.notify("audio_playback_started", self._current_item)
            
            # 记录播放信息
            self.logger.info(f"开始播放音频: {audio_item.title[:30]}...")
            
            # 使用设备详细信息进行播放
            if self._device_info:
                self.logger.info(f"使用设备 {self._output_device} 播放音频")
                if isinstance(self._device_info, dict):
                    # 记录使用的设备信息
                    self.logger.debug(f"设备ID: {self._device_info.get('id', 'unknown')}")
            else:
                self.logger.info(f"使用默认设备播放音频")
            
            # 获取最新的音量设置，优先级：音频项 > 配置服务 > AppConfig > 内存缓存
            config_volume = self._volume  # 默认使用当前内存中的音量
            
            # 尝试从配置服务获取最新音量设置
            config_service = ServiceLocator.get(IConfigService)
            if config_service:
                try:
                    service_volume = config_service.get("audio.volume")
                    if service_volume is not None:
                        config_volume = float(service_volume)
                        self.logger.info(f"从配置服务获取音量: {config_volume}")
                except (ValueError, TypeError) as e:
                    self.logger.warning(f"从配置服务获取音量失败: {str(e)}")
            
            # 如果从配置服务获取不到，尝试从AppConfig获取
            if config_volume == self._volume:
                config = AppConfig.get_instance()
                app_volume = config.get("audio", "volume", self._volume)
                if app_volume != self._volume:
                    config_volume = app_volume
                    self.logger.info(f"从AppConfig获取音量: {config_volume}")
            
            
            # 更新内存缓存的音量
            if config_volume != self._volume:
                self.logger.info(f"更新音量设置：从 {self._volume} 到 {config_volume}")
                self._volume = config_volume
            
            # 优先使用音频项的音量设置，否则使用配置音量
            volume = audio_item.metadata.get("volume", self._volume)
            
            # 确保音量不超过安全值
            if volume > 0.95:
                self.logger.warning(f"音频项音量 {volume} 超过安全值0.95，将被调整")
                volume = 0.95
            
            # 设置媒体播放器的音量
            self._media_player.set_volume(volume)
            self.logger.info(f"使用音量播放: {volume}")
            
            # 停止当前播放
            self._media_player.stop()
            
            # 直接使用play方法播放音频，PyAudioPlayer不需要先set_media
            result = self._media_player.play(audio_item.file_path)
            
            # 记录播放信息
            if result:
                self.logger.info(f"实际播放音频文件: {audio_item.file_path}")
            else:
                self.logger.error(f"播放音频文件失败: {audio_item.file_path}")
            
            return result
        except Exception as e:
            self.logger.error(f"播放音频失败: {str(e)}")
            traceback.print_exc()
            
            # 如果播放失败，重置当前播放的音频项
            if self._current_item:
                self._current_item.error = str(e)
                self._current_item = None
            
            return False

    def _initialize_main_speech_manager(self) -> bool:
        """
        统一管理主话术管理器的初始化/更新/重载
        
        @return: 是否成功初始化/更新主话术管理器
        """
        # 获取配置服务和配置路径
        config_service = ServiceLocator.get(IConfigService)
        if not config_service:
            self.logger.warning("配置服务不可用，无法初始化主话术管理器")
            return False
            
        config_path = config_service.get("app.config_path")
        if not config_path or not os.path.exists(config_path):
            self.logger.warning(f"未找到有效的配置路径: {config_path}")
            return False
            
        try:
            # 统一的初始化/更新逻辑
            if not self.main_speech_manager:
                self.logger.info(f"初始化主话术管理器，配置路径: {config_path}")
                self.main_speech_manager = MainSpeechManager(config_path)
            elif self.main_speech_manager.config_path != config_path:
                self.logger.info(f"更新主话术管理器配置路径: {config_path}")
                self.main_speech_manager = MainSpeechManager(config_path)
            else:
                self.logger.info(f"重新加载主话术，配置路径: {config_path}")
                self.main_speech_manager.reload()
                
            # 记录加载信息
            self.logger.info(f"已加载主话术文件: {len(self.main_speech_manager._main_speeches)}个")
            return True
        except Exception as e:
            self.logger.error(f"初始化主话术管理器失败: {str(e)}")
            traceback.print_exc()
            return False

    def initialize(self) -> bool:
        """
        初始化音频服务
        """
        try:
            self.logger.info("开始初始化音频服务...")
            
            # 获取配置服务
            config_service = ServiceLocator.get(IConfigService)
            
            # 获取状态管理器
            self.state_manager = ServiceLocator.get(AppStateManager)
            if not self.state_manager:
                self.logger.error("无法获取状态管理器，状态更新将仅通过事件传递")
            
            # 使用统一的方法初始化主话术管理器
            self._initialize_main_speech_manager()
            
            # 初始化TTS相关配置
            if config_service:
                # 获取TTS配置
                tts_url = config_service.get("tts.url") or "http://localhost:9000/tts"
                tts_api_key = config_service.get("tts.api_key") or ""
                tts_timeout = config_service.get("tts.timeout") or 10
                
                # 更新配置
                self._config["tts_url"] = tts_url
                self._config["tts_api_key"] = tts_api_key
                self._config["tts_timeout"] = tts_timeout
                
                # 检查TTS服务连接状态
                is_connected = self._check_tts_connection()
                if is_connected:
                    self.logger.info(f"TTS服务连接成功: {tts_url}")
                    self._tts_connected = True
                else:
                    self.logger.warning(f"TTS服务连接失败: {tts_url}")
                    self._tts_connected = False
                
                # 更新TTS连接状态
                connection_status = StateValues.CONNECTED if is_connected else StateValues.DISCONNECTED
                
                # 同时通过状态管理器和事件系统更新状态
                if self.state_manager:
                    self.state_manager.set_state(StateType.AUDIO_SERVICE, connection_status)
                
                # 触发TTS连接状态事件
                self.notify("audio_service_status_changed", "已连接" if is_connected else "未连接")
                
                # 启动TTS连接检查线程
                self._start_tts_check_thread()
            
            # 从配置服务获取音频输出设备设置
            if config_service:
                # 获取设备名称
                output_device = config_service.get("audio.output")  # 与ConfigPanel中的键名保持一致
                if output_device:
                    # 应用输出设备设置
                    self._set_output_device(output_device)
                    self.logger.info(f"从配置服务加载音频输出设备: {output_device}")
            
            self.logger.info("音频服务初始化完成")
            return True
        except Exception as e:
            self.logger.error(f"初始化音频服务失败: {str(e)}")
            traceback.print_exc()
            return False

    def _set_output_device(self, output_device: str) -> None:
        """
        设置音频输出设备
        
        @param output_device: 输出设备名称
        """
        # 记录更新信息
        self.logger.info(f"更新音频输出设备: {output_device}")
        
        # 如果设备没有变化，不需要处理
        if self._output_device == output_device:
            self.logger.debug(f"设备未变化，仍然使用: {output_device}")
            return
            
        # 记录当前播放状态
        currently_playing = None
        current_position = 0
        
        if self._current_item and self._current_item.is_playing and not self._current_item.is_paused:
            currently_playing = self._current_item
            # 尝试获取当前播放位置 (虽然当前版本不支持恢复位置)
            try:
                current_position = self._media_player.get_position() or 0
                self.logger.info(f"保存当前播放状态: {currently_playing.title[:30]}..., 位置: {current_position:.2f}秒")
            except Exception as e:
                self.logger.warning(f"获取当前播放位置失败: {str(e)}")
                
            # 停止当前播放
            self._media_player.stop()
        
        # 保存旧设备名称用于通知
        old_device = self._output_device
        
        # 保存设备名称
        self._output_device = output_device
        
        # 尝试在PyAudioPlayer中设置输出设备
        try:
            if hasattr(self._media_player, 'set_output_device'):
                success = self._media_player.set_output_device(output_device)
                if success:
                    # 重要：获取并保存设备详细信息，以便在播放时使用
                    if hasattr(self._media_player, '_device_info'):
                        self._device_info = self._media_player._device_info
                        self.logger.info(f"已获取设备详细信息: {str(self._device_info)[:100]}...")
                    else:
                        # 如果无法直接获取，则创建一个简单的设备信息对象
                        self._device_info = {"name": output_device, "id": output_device}
                        self.logger.info(f"已创建简单设备信息: {output_device}")
                    
                    self.logger.info(f"已在媒体播放器中设置输出设备: {output_device}")
                else:
                    self.logger.warning(f"设置输出设备失败，可能不存在该设备: {output_device}")
                    # 设置失败时清除设备信息
                    self._device_info = None
        except Exception as e:
            self.logger.error(f"设置媒体播放器输出设备失败: {str(e)}")
            # 出错时清除设备信息
            self._device_info = None
        
        # 触发设备变更事件通知
        try:
            self.notify("audio_device_changed", {
                "old_device": old_device,
                "new_device": output_device
            })
        except Exception as e:
            self.logger.error(f"发送设备变更通知失败: {str(e)}")

        # 更新应用状态
        try:
            # 更新AppStateManager（保持与现有的兼容）
            try:
                AppStateManager.instance().set_state(StateType.AUDIO_OUTPUT, output_device)
            except Exception as e:
                self.logger.error(f"更新AppStateManager失败: {str(e)}")
            
            # 更新StatusMonitorModel
            try:
                from app.models.status_monitor_model import StatusMonitorModel, StatusType as MonitorStatusType
                StatusMonitorModel.instance().update_state(MonitorStatusType.AUDIO_OUTPUT, output_device)
            except Exception as e:
                self.logger.error(f"更新StatusMonitorModel失败: {str(e)}")
            
            self.logger.info(f"音频输出设备状态已更新: {output_device}")
        except Exception as e:
            self.logger.error(f"更新状态管理器失败: {str(e)}")
            traceback.print_exc()
        
        # 如果之前有音频在播放，使用新设备重新开始播放
        if currently_playing:
            self.logger.info(f"使用新设备 {output_device} 重新播放: {currently_playing.title[:30]}...")
            self._play_audio(currently_playing)
        else:
            self.logger.debug(f"已设置音频输出设备: {self._output_device}")
    
    def get_output_devices(self) -> List[str]:
        """
        获取可用的音频输出设备列表
        
        @return: 设备名称列表
        """
        try:
            # 初始化结果列表，始终添加默认设备作为第一项
            result = ["默认设备"]
            seen_devices = set()  # 用于跟踪已添加设备
            
            # 如果PyAudioPlayer有获取设备列表的方法，则使用它
            if hasattr(self._media_player, 'get_output_devices'):
                device_list = self._media_player.get_output_devices()
                self.logger.info(f"原始设备列表中有 {len(device_list)} 个设备")
                
                # 处理每个设备
                for device in device_list:
                    device_name = None
                    
                    # 从字典或字符串中获取设备名称
                    if isinstance(device, dict) and 'name' in device:
                        device_name = device['name']
                    elif isinstance(device, str):
                        device_name = device
                    
                    # 跳过空设备名
                    if not device_name or device_name == "默认设备":
                        continue
                    
                    # 修复可能存在的乱码
                    try:
                        # 处理特定中文乱码模式
                        if any(x in device_name for x in ['鑰', '鎺', '榄', '緒', '涓', '杩']):
                            # 常见的乱码替换
                            replacements = {
                                '鑰虫満': '耳机',
                                '榄呭０': '魅声',
                                '鎺ュ彛': '接口',
                                '杩為害': '连接',
                                '涓撶敤': '专用'
                            }
                            
                            # 应用替换
                            for bad, good in replacements.items():
                                if bad in device_name:
                                    device_name = device_name.replace(bad, good)
                    except Exception as e:
                        self.logger.warning(f"修复设备名称编码失败: {str(e)}")
                    
                    # 跳过包含特殊系统路径的设备
                    if '@system32' in device_name.lower() or 'hands-free' in device_name.lower():
                        continue
                    
                    # 跳过太短的设备名称(通常是无效条目)
                    if len(device_name.strip()) <= 2:
                        continue
                    
                    # 创建规范化名称用于去重
                    norm_name = device_name.lower().replace(' ', '')
                    
                    # 如果该设备或类似设备已添加，则跳过
                    if norm_name in seen_devices:
                        continue
                    
                    # 添加设备到结果列表
                    result.append(device_name)
                    seen_devices.add(norm_name)
                    self.logger.debug(f"添加设备: {device_name}")
            else:
                self.logger.warning("媒体播放器不支持获取设备列表方法")
                
                # 尝试使用PyQt5方式获取设备列表
                try:
                    from PyQt5.QtMultimedia import QAudioDeviceInfo, QAudio
                    devices = QAudioDeviceInfo.availableDevices(QAudio.AudioOutput)
                    
                    for device in devices:
                        device_name = device.deviceName()
                        if device_name and device_name != "默认设备" and device_name.lower() not in seen_devices:
                            result.append(device_name)
                            seen_devices.add(device_name.lower())
                            self.logger.debug(f"使用PyQt5添加设备: {device_name}")
                except Exception as e:
                    self.logger.error(f"尝试使用PyQt5获取设备列表失败: {str(e)}")
            
            self.logger.info(f"成功获取 {len(result)} 个有效的音频输出设备")
            return result
        except Exception as e:
            self.logger.error(f"获取音频输出设备列表失败: {str(e)}")
            traceback.print_exc()
            # 出错时返回默认设备
            return ["默认设备"] 

    def _on_config_updated(self, config_name: str, value: Any) -> None:
        """
        配置更新事件处理
        
        @param config_name: 配置项名称
        @param value: 配置值
        """
        try:
            if config_name == "speech_source":
                # 更新主话术管理器的话术来源
                if self.main_speech_manager:
                    self.main_speech_manager.set_speech_source(value)
                    self.logger.info(f"已更新主话术管理器的话术来源: {value}")
                    
                    # 触发队列更新事件
                    self._notify_listeners("queue_updated", Event("queue_updated", None))
            elif config_name == "audio_volume":
                # 更新音量
                self._volume = value
                self._media_player.set_volume(value)
                self.logger.info(f"已更新音量: {value}")
        except Exception as e:
            self.logger.error(f"处理配置更新失败: {str(e)}")